#!/bin/bash

# 当前版本
SFSSHX_VERSION=1.1.0

# 监测依赖
command -v md5sum >/dev/null 2>&1 || { echo >&2 "[md5sum] is required, please install."; exit 1; }
command -v expect >/dev/null 2>&1 || { echo >&2 "[expect] is required, please install."; exit 1; }
command -v bc >/dev/null 2>&1 || { echo >&2 "[bc] is required, please install."; exit 1; }
command -v ssh >/dev/null 2>&1 || { echo >&2 "[ssh] is required, please install."; exit 1; }

# 帮助
usage() {
    echo 'NAME'
    echo 'sshx -- safe ssh soft.'
    echo ''
    echo 'SYNOPSIS'
    echo 'sshx [-n NAME] [-s SECRET] [-o OPERATION]'
    echo ''
    echo 'DESCRIPTION'
    echo 'sshx save the encrypted content(host,port,user,password) to a local file, easy resolve and connect to server.'
    echo "Because of resolve depends on the name & secret, so it's safe!"
    echo ''
    echo 'The options are as follows:'
    echo '  -h    show help'
    echo '  -n string'
    echo '        Connect name'
    echo '  -o string'
    echo '        operation:[add|del|con] (default con)'
    echo '  -s string'
    echo '        Connect secret'
    echo '  -v    show version'
}

# md5
sxMd5sum() {
    echo -n "${1}" | md5sum | cut -d ' ' -f1
}

# 字符串 -> 16进制 -> 10进制
sxStrHexDec() {
    hex=`sxMd5sum ${1}`
    hex=`echo -n ${hex}| tr a-z A-Z`
    dec=`echo "ibase=16; ${hex}" | bc`
    echo $dec
}

# 加密
sxEncode() {

    # 获取10进制密钥
    secret=`sxStrHexDec $2`

    # 将10进制密钥base64后和内容为待加密内容
    content=`echo "${secret}" |base64`"@"${1}

    # 转16进制 添加-n 避免换行符转 0x0A
    hex=`echo -n "${content}" | xxd -ps -u -c 5000`
    
    # 转10进制
    info=`echo "ibase=16; ${hex}" | bc`

    # 密文与密钥相加
    result=`echo "ibase=10;obase=10;${secret}+${info}"|bc`

    # 拼接内容
    echo "${result}"
    return 0
}

# 解密
sxDecode() {

    # 获取10进制密钥
    secret=`sxStrHexDec $2`

    # 替换特殊字符
    content=$1
    
    # 加密内容减密钥得到十进制密文
    private=`echo "ibase=10;obase=10; ${content}-${secret}"|bc`
    
    # 十进制转十六进制
    base=`echo "ibase=10; obase=16; ${private}" | bc`

    # 转为原字符串
    base=`echo $base | xxd -ps -u -r`

    result=${base#*@}

    echo $result
    return 0
}

# 添加链接
sxAddConfig() {
    if [ -f "${SFSSHX_FULL_FILE}" ];then
        echo 'File already exist, add fail'
        exit 1
    fi

    host=""
    while [ ${#host} -eq 0 ]
    do
        echo -n " host: "
        read host
        done
   
    echo -n " port[22]: "
    read port
    if [ ${#port} -eq 0 ]; then
        port=22
    fi

    echo -n " user[root]: "
    read user
    if [ ${#user} -eq 0 ]; then
        user='root'
    fi
    
    password=""
    while [ ${#password} -eq 0 ]
    do
        stty -echo
        echo -n " password: "
        read password
        done
    stty echo
    echo ''

    # 拼接加密串
    params=`echo "${host}" |base64`"@"`echo "${port}" |base64`"@"`echo "${user}" |base64`"@"`echo "${password}" |base64`
    
    # 获取密文
    result=`sxEncode ${params} $SFSSHX_SECRET_KEY`
    if [ $? != "0" ];then
        echo "Encode content fail!"
        exit 1
    fi
    result="v${SFSSHX_VERSION}v${result}"

    # 写入存储文件
    echo $result > $SFSSHX_FULL_FILE
    exit 0;
}

# 建立连接
sxConnect() {
    if [ ! -f "${SFSSHX_FULL_FILE}" ];then
        echo 'File dos not exist, connect fail!'
        exit 1
    fi
    
    # 读文件内容
    content=`cat ${SFSSHX_FULL_FILE}`
    content=${content##*v}
    content=${content//' '/''}
    content=${content//'\'/''}

    # 解密为字符串
    base=`sxDecode ${content} ${SFSSHX_SECRET_KEY}`
    if [ $? != "0" ];then
        echo "Decode content fail!"
        exit 1
    fi

    # 分割字符串
    pass=`echo -n "${base}" | cut -d '@' -f4 | base64 --decode`
    if [ -z "$pass" ]; then 
        echo "Has Not Password"
        exit 1
    fi
    user=`echo -n "${base}" | cut -d '@' -f3| base64 --decode`
    port=`echo -n "${base}" | cut -d '@' -f2| base64 --decode`
    host=`echo -n "${base}" | cut -d '@' -f1| base64 --decode`

    if [ -z "$TMPDIR" ]; then
        exp=$(mktemp --tmpdir sfsshx-XXX.exp)
    else
        exp=$TMPDIR"/sfsshx-000.exp"
    fi

    echo '#!/usr/bin/expect -f' > $exp
    echo 'set timeout -1' >> $exp
    echo 'spawn ssh -o StrictHostKeyChecking=no -p $env(SFSSHX_SIN_PORT) $env(SFSSHX_SIN_USER)@$env(SFSSHX_SIN_HOST);' >> $exp
    echo 'expect {' >> $exp
    echo '"*yes/no" { send "yes\r"; exp_continue}' >> $exp
    echo '"*password:" { send "$env(SFSSHX_SIN_PASS)\r" }' >> $exp
    echo '}' >> $exp
    echo 'interact' >> $exp

    # 连接
    export SFSSHX_SIN_HOST=$host && export SFSSHX_SIN_PORT=$port \
    && export SFSSHX_SIN_USER=$user && export SFSSHX_SIN_PASS=$pass \
    && expect -f ${exp} \
    && rm -rf ${exp}
}

sxDelete() {
    if [ ! -f "${SFSSHX_FULL_FILE}" ];then
        echo 'File dos not exist, delete fail!'
        exit 1
    fi

    echo -n " delete ${SFSSHX_FULL_FILE} [N|Y]: "
    read operation
    if [ ${#operation} -eq 0 ]; then
        operation=N
    fi

    operation=`echo -n ${operation}| tr a-z A-Z`

    if [ "$operation" == "Y" ]; then
        rm -rf ${SFSSHX_FULL_FILE}
    fi
}

# 获取参数
while getopts ":n:s:o:v:h:" opt
do
    case $opt in
        n) SFSSHX_CONNECT_NAME=$OPTARG ;;
        s) SFSSHX_SECRET_KEY=$OPTARG ;;
        o) SFSSHX_OPERATION=$OPTARG ;;
        v) echo $SFSSHX_VERSION ;;
        h) usage && exit 0 ;;
        ?) usage && exit 0 ;;
    esac
done

# 指定连接名称
while [ ${#SFSSHX_CONNECT_NAME} -eq 0 ]
do
    echo -n " connect name: "
    read SFSSHX_CONNECT_NAME
    done

# 指定密钥
while [ ${#SFSSHX_SECRET_KEY} -eq 0 ]
do
    echo -n " connect secret: "
    read SFSSHX_SECRET_KEY
    done

# 操作
if [ ! -n "$SFSSHX_OPERATION" ] ;then
    SFSSHX_OPERATION="con"
fi

# 密码存储目录
SFSSHX_FOLDER_NAME="${HOME}/.sfsshx/${SFSSHX_VERSION}/"

# 存储目录
if [ ! -d "${SFSSHX_FOLDER_NAME}" ]; then
    mkdir -p ${SFSSHX_FOLDER_NAME}
fi

# 文件名
SFSSHX_FULL_FILE="${SFSSHX_FOLDER_NAME}"`sxMd5sum ${SFSSHX_CONNECT_NAME}`".sx"

if [ "$SFSSHX_OPERATION" == "add" ]; then
    sxAddConfig
elif [ "$SFSSHX_OPERATION" == "del" ]; then
    sxDelete
elif [ "$SFSSHX_OPERATION" == "con" ]; then
    sxConnect
else
    echo "what's your operation?";
fi
exit 0